package com.imooc.controller;

import com.imooc.enums.YesOrNo;
import com.imooc.pojo.Carousel;
import com.imooc.pojo.Category;
import com.imooc.pojo.vo.CategoryVO;
import com.imooc.pojo.vo.NewItemsVO;
import com.imooc.service.CarouselService;
import com.imooc.service.CategoryService;
import com.imooc.utils.IMOOCJSONResult;
import com.imooc.utils.JsonUtils;
import com.imooc.utils.RedisOperator;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("index")
@Api(value = "首页", tags = {"首页展示相关的接口"})
public class IndexController {

    @Autowired
    private CarouselService carouselService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private RedisOperator redisOperator;

    @ApiOperation(value = "获取首页轮播图的列表", notes = "获取首页轮播图的列表", httpMethod = "GET")
    @GetMapping("/carousel")
    public IMOOCJSONResult carousel() {
        //如果拿到了这个缓存
        String carouselStr = redisOperator.get("carousel");
        List<Carousel> list;
        if (StringUtils.isBlank(carouselStr)) {
            //redis为空,则查询数据库
            list = carouselService.queryAll(YesOrNo.YES.type);
            //这里把list转换为JSON字符串,保存在redis里
            redisOperator.set("carousel", JsonUtils.objectToJson(list));
        } else {
            //如果有缓存,这需要把字符串转换为JSONList
            list = JsonUtils.jsonToList(carouselStr, Carousel.class);
        }

        //这里直接把list转给前端处理,并且在构造方法中我们可以看到他是封装到了data里,前端会处理这个数据
        return IMOOCJSONResult.ok(list);
    }

    /**
     * 如何更新缓存?
     * 1.后台运营系统,一旦广告发生更改(轮播图),就可以删除缓存,然后重置
     * 2.定时任务,比如每天凌晨三点重置,如果有很多缓存,不要一次性都重置,这样会加大数据库压力,可以批量重置
     * 3.每个轮播图都有可能是广告,可以有时间段付费,每个广告都设置一个过期时间,直到过期才重置
     *
     */

    //分类也可以缓存

    /**
     * 首页分类展示的需求
     * 1.第一次刷新主页只需要查询主分类
     * 2.只有当鼠标第一次移动到主分类目录下,才会发出获得子分类的请求,如果存在子分类不会加载(懒加载)lazy load
     */
    @ApiOperation(value = "获取商品分类", notes = "获取首页轮播图的列表", httpMethod = "GET")
    @GetMapping("/cats")
    public IMOOCJSONResult cats() {

        //首先看redis有没有缓存
        String catsStr = redisOperator.get("cats");
        List<Category> list;
        if (StringUtils.isBlank(catsStr)) {
            //redis为空,则查询数据库
            list = categoryService.queryAllRootLevelCat();
            //这里把list转换为JSON字符串,保存在redis里
            redisOperator.set("cats", JsonUtils.objectToJson(list));
        } else {
            //如果有缓存,这需要把字符串转换为JSONList
            list = JsonUtils.jsonToList(catsStr, Category.class);
        }
        //这里直接把list转给前端处理,并且在构造方法中我们可以看到他是封装到了data里,前端会处理这个数据
        return IMOOCJSONResult.ok(list);
    }

    //子分页可以缓存,更新频率不高
    @ApiOperation(value = "获取商品的子分类", notes = "获取商品的子分类", httpMethod = "GET")
    @GetMapping("/subCat/{rootCatId}")
    public IMOOCJSONResult subCat(
            @ApiParam(name = "rootCatId", value = "一级分类id", required = true)
            @PathVariable Integer rootCatId) {
        if (rootCatId == null) {
            return IMOOCJSONResult.errorMsg("分类不存在");
        }

        //首先看redis有没有缓存,这里的子分类要注意,根据rootCatId进行绑定区分,因为有多个子分类,不然会混淆
        String subCatStr = redisOperator.get("subCat:" + rootCatId);
        List<CategoryVO> list;
        if (StringUtils.isBlank(subCatStr)) {
            //redis为空,则查询数据库
            list = categoryService.getSubCatList(rootCatId);
            if (list != null && list.size() > 0) {
                //我们加上这个list判空是因为如果用户请求了数据库不存在的数据,我们为了防止他直接进入数据库可以设置空缓存
                redisOperator.set("subCat:" + rootCatId, JsonUtils.objectToJson(list));
            }
            //这里把list转换为JSON字符串,保存在redis里
            //保护数据库,缓存无法穿透
            else {
                redisOperator.set("subCat:" + rootCatId, JsonUtils.objectToJson(list), 5 * 60);
            }

        } else {
            //如果有缓存,这需要把字符串转换为JSONList
            list = JsonUtils.jsonToList(subCatStr, CategoryVO.class);
        }

        //这里直接把list转给前端处理,并且在构造方法中我们可以看到他是封装到了data里,前端会处理这个数据
        return IMOOCJSONResult.ok(list);
    }

    @ApiOperation(value = "查询每个一级分类下最新的六条商品数据", notes = "查询每个一级分类下最新的六条商品数据", httpMethod = "GET")
    @GetMapping("/sixNewItems/{rootCatId}")
    public IMOOCJSONResult sixNewItems(
            @ApiParam(name = "rootCatId", value = "一级分类id", required = true)
            @PathVariable Integer rootCatId) {
        if (rootCatId == null) {
            return IMOOCJSONResult.errorMsg("分类不存在");
        }
        List<NewItemsVO> list = categoryService.getSixNewItemsLazy(rootCatId);
        //这里直接把list转给前端处理,并且在构造方法中我们可以看到他是封装到了data里,前端会处理这个数据
        return IMOOCJSONResult.ok(list);
    }
}